#include <cstdio>
#include "graphviewer.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

#include "Vertex.h"
#include "Edge.h"

using namespace std;

const int INT_INFINITY = 2147483647;


struct vertex_greater_than {
	bool operator()(Vertex a, Vertex b) const {
		return a.getCustAcum() > b.getCustAcum();
	}
};


//!  lerFicheiro
/*!
 * Funcao que le do ficheiro.
 */
//




vector<Vertex> estacoes;
vector<Edge> arestas;

vector<string> lerFicheiro(string nomeFicheiro)
				{

	string linha;
	vector<string> linhas;
	ifstream infile;

	if(nomeFicheiro == "stations.txt") infile.open("stations.txt");
	else if(nomeFicheiro == "edges.txt") infile.open("edges.txt");

	//! Ler linhas do ficheiro
	/*!
	 * Cada uma das linhas do ficheiro .txt e guardada numa string, que e consequentemente guardado num
	 * vector de strings.
	 */


	while(!infile.eof()) // To get you all the lines.
	{
		getline(infile,linha); // Saves the line in STRING.
		cout<<linha; // Prints our STRING.
		linhas.push_back(linha);
	}
	infile.close();
	return linhas;


				}


//! lerEstacoes()
/*!
 * Cada uma das linhas do ficheiro e separada e guardado,
 * respectivamente, nas variaveis id e nome.
 */
//

void lerEstacoes()
{

	vector<string> estac_temp = lerFicheiro("stations.txt");



	for(unsigned int i=0; i<estac_temp.size();i++)
	{

		stringstream ss;
		ss << estac_temp[i];

		char* tmp;
		ss >> tmp;

		char *p = strtok(tmp, ";");

		int id = atoi(p);
		int tam = strlen(p);


		p = strtok(p,";");
		string nome = (p+1+tam);


		cout  << id << " " << nome << endl;
		estacoes.push_back(Vertex(nome,id));  //adicicao dos nos no vector de nos


	}


}


//! procuraVertice(int id)
/*!
 * Funcao que procura no vector estacoes (vertices), uma estacao,
 * atraves do seu id.
 */
//


Vertex procuraVertice(int id)
{
	Vertex procuro;

	for (unsigned int v = 0; v<estacoes.size(); v++)
	{
		if (estacoes[v].getId() == id)
		{
			procuro = estacoes[v];
			break;
		}

	}
	return procuro;
}

//! Tokenize(const string& str,vector<string>& tokens, string del)
/*!
 * Funcao que retorna por referencia um vector com todas as substrings que
 * estavam separadas pela string del.
 */
//

void Tokenize(const string& str,vector<string>& tokens, string del)
{
	string delimiters = del;

	// Skip delimiters at beginning.
	string::size_type lastPos = str.find_first_not_of(delimiters, 0);
	// Find first "non-delimiter".
	string::size_type pos     = str.find_first_of(delimiters, lastPos);

	while (string::npos != pos || string::npos != lastPos)
	{
		// Found a token, add it to the vector.
		tokens.push_back(str.substr(lastPos, pos - lastPos));
		// Skip delimiters.  Note the "not_of"
		lastPos = str.find_first_not_of(delimiters, pos);
		// Find next "non-delimiter"
		pos = str.find_first_of(delimiters, lastPos);
	}
}


//! lerArestas()
/*!
 * Divide as string lidas do ficheiro edges.txt, em arestas, adicionamdo-as
 * ao vector de arestas, de Edges, declarado anteriormente.
 */

void lerArestas()
{
	vector<string> linhas = lerFicheiro("edges.txt");


	for (unsigned int i = 0; i<linhas.size(); i++)
	{
		vector<string> parse;
		Tokenize(linhas[i], parse, " ");

		for(int unsigned j = 2; j< (parse.size()-1); j+=3)
		{
			int id1 = atoi(parse[j].c_str());  //id do vertice inicial

			int id2 = atoi(parse[j+3].c_str()); // id do vertice final

			int id_aresta = atoi(parse[j+1].c_str());

			string nome_aresta = parse[0];
			string cor_aresta = parse[1];

			Vertex inicio = procuraVertice(id1);
			Vertex fim = procuraVertice(id2);

			Edge aresta_i = Edge(nome_aresta, cor_aresta,id_aresta, atof(parse[j+2].c_str()),inicio, fim);
			//Edge aresta_v = Edge(nome_aresta, cor_aresta, atoi(parse[j+1].c_str()),atof(parse[j+2].c_str()),fim, inicio);


			arestas.push_back(aresta_i);
			//arestas.push_back(aresta_v);


			//associa as arestas a cada um dos nos

			for (unsigned int v = 0; v<estacoes.size(); v++)
			{
				if (estacoes[v].getId() == id1)
				{
					estacoes[v].addEdge(id_aresta);
				}

				if (estacoes[v].getId() == id2)
				{
					estacoes[v].addEdge(id_aresta);
				}

			}
		}
	}
}

//! Dijkstra's algorithm
/*!
 * Adaptation of Dijkstra's algorithm
 */

/*

void dijkstraShortestPath(int s) {

	for(unsigned int i = 0; i < estacoes.size(); i++) {
		//estacoes[i].setPath(NULL);
		estacoes[i].setCustAcum(INT_INFINITY);
		estacoes[i].setProcessing(false);
	}

	Vertex v = procuraVertice(s);
	v.setCustAcum(0);

	vector< Vertex > pq;
	pq.push_back(v);


	make_heap(pq.begin(), pq.end());


	while( !pq.empty() ) {

		v = pq.front();
		pop_heap(pq.begin(), pq.end());
		pq.pop_back();

		for(unsigned int i = 0; i < v.getId_edges().size(); i++) {
			Vertex w = arestas[v.getId_edges()[i]-1].findNext(v);

			if(v.getCustAcum() + arestas[v.getId_edges()[i]-1].getCusto() < w.getCustAcum() ) {

				w.setCustAcum(v.getCustAcum() + arestas[v.getId_edges()[i]-1].getCusto());
				w.addToPath(v);

				// Se já estiver na lista, apenas a actualiza
				if(!w.getProcessing())
				{
					w.setProcessing(true);
					pq.push_back(w);
				}

				make_heap (pq.begin(),pq.end(),vertex_greater_than());
			}
		}
	}
}

 */



int main() {

	lerEstacoes();
	lerArestas();

	//! Janela.
	/*!
	 * Criacao da janela.
	 */

	GraphViewer *gv = new GraphViewer(600, 600, true, 7772);
	gv->createWindow(600, 600);

	//!  Background.
	/*!
	 * Configuracao de uma imagem de fundo.
	 */

	gv->setBackground("porto.png");



	for (unsigned int k = 0 ; k < arestas.size(); k++)
	{
		if(arestas[k].getCor() == "blue")
		{

			int idNo = arestas[k].getInicio().getId();
			int idAresta = arestas[k].getIdEdge();


			gv->defineEdgeColor("blue");
			gv->defineVertexColor("lightGray");
			gv->addNode(idNo);
			gv->rearrange();

			int idNoOrigem = arestas[k].getInicio().getId();
			int idNoDest = arestas[k].getFim().getId();

			//gv->addEdge(idAresta,idNoOrigem,idNoDest, EdgeType::DIRECTED);
			gv->addEdge(idAresta,idNoOrigem,idNoDest,EdgeType::UNDIRECTED);
		}

		if(arestas[k].getCor() == "red")
		{
			int idNo = arestas[k].getInicio().getId();
			int idAresta = arestas[k].getIdEdge();


			gv->defineEdgeColor("red");
			gv->defineVertexColor("lightGray");
			gv->addNode(idNo);
			gv->rearrange();

			int idNoOrigem = arestas[k].getInicio().getId();
			int idNoDest = arestas[k].getFim().getId();


			gv->addEdge(idAresta,idNoOrigem,idNoDest,EdgeType::UNDIRECTED);

		}

		/*if(arestas[k].getCor() == "yellow")
		{
			int idNo = arestas[k].getInicio().getId();

			gv->defineEdgeColor("yellow");
			gv->defineVertexColor("lightGray");
			gv->addNode(idNo);
			gv->rearrange();

		}

		if(arestas[k].getCor() == "pink")
		{
			int idNo = arestas[k].getInicio().getId();

			gv->defineEdgeColor("pink");
			gv->defineVertexColor("lightGray");
			gv->addNode(idNo);
			gv->rearrange();

		}
		if(arestas[k].getCor() == "orange")
		{
			int idNo = arestas[k].getInicio().getId();

			gv->defineEdgeColor("orange");
			gv->defineVertexColor("lightGray");
			gv->addNode(idNo);
			gv->rearrange();

		}*/
	}


	//ifstream inFile;

	//!  Nodes.
	/*!
	 *  Reads all the nodes from the text file, including the nodes' names.
	 */
	/*inFile.open("stations.txt");

	if (!inFile) {
		cerr << "Unable to open file datafile.txt";
		exit(1);   // call system to stop
	}

	std::string   line;

	int idNo=0;
	string label;

	while(std::getline(inFile, line))
	{
		std::stringstream linestream(line);
		std::string data;

		linestream >> idNo;

		std::getline(linestream, data, ' ');  // read up-to the first ; (discard ;).
		linestream >> label;



		gv->addNode(idNo);
		//gv->setVertexLabel(idNo,label);

	}

	inFile.close();*/

	//gv->rearrange();


	//!  Edges.
	/*!
      Reads all the edges and edges' informations from the text file.
	 */
	/*inFile.open("edges.txt");

	if (!inFile) {
		cerr << "Unable to open file datafile.txt";
		exit(1);   // call system to stop
	}




	//while(std::getline(inFile, line))
	//{
	std::stringstream linestream(line);
	std::string data;

	while(!inFile.eof()) // To get you all the lines.
	{
		getline(inFile,data); // Saves the line in STRING.
		cout<<data << endl; // Prints our STRING.
	}

	string linha;

	// linestream >> linha;

	//	  cout << "Linha: " << linha << endl;

	/*std::getline(linestream, data, ';');  // read up-to the first ; (discard ;).
  		    linestream >> idNoOrigem;
  		    std::getline(linestream, data, ';');  // read up-to the first ; (discard ;).
  		    linestream >> idNoDestino;

	 */



	//inFile.close();


	gv->rearrange();






	getchar();

	return 0;

}

